﻿using System;
using RaytracerLib.MathLib;
using YAXLib;
using RaytracerLib.Rays;
using System.Diagnostics;
using TomanuExtensions;
using RaytracerLib;

namespace RaytracerLib.Cameras
{
    public abstract class PlaneCamera : Camera
    {
        [YAXNode]
        public double MinimalPlaneDistant = 1.0;
        
        /// <summary>
        /// In deg
        /// </summary>
        [YAXNode]
        public double FOV = 45.0;

        protected double m_viewport_width;
        protected double m_viewport_height;

        public PlaneCamera(Vector3 a_right, Vector3 a_up) :
            base(a_right, a_up)
        {
            Name = "Plane camera";
        }

        protected override void RenderStart(RenderStartPhase a_phase)
        {
            base.RenderStart(a_phase);

            if (a_phase == RenderStartPhase.PrepareObjectToRender)
            {
                m_viewport_height = 2.0 * MinimalPlaneDistant * Math.Tan(MathExtensions.ToRad(FOV) / 2.0);
                m_viewport_width = m_viewport_height * Film.Width / Film.Height;
            }
        }

        public override void ScaleAbsolute(double a_scale)
        {
            MinimalPlaneDistant *= a_scale;

            base.ScaleAbsolute(a_scale);
        }

        protected override AABB GetLocalBoundBox()
        {
            return new AABB(new Vector3(-m_viewport_width / 2, -m_viewport_height / 2, 0),
                            new Vector3(m_viewport_width / 2, m_viewport_height / 2, MinimalPlaneDistant));
        }

        internal override Vector2 UVToPixel(Vector2 a_uv)
        {
            Debug.Assert(DoubleExtensions.InRange(a_uv.X, 0, 1));
            Debug.Assert(DoubleExtensions.InRange(a_uv.Y, 0, 1));

            return new Vector2(a_uv.X * Film.Width, a_uv.Y * Film.Height);
        }

        internal override Vector2 PixelToUV(Vector2 a_pixel)
        {
            Debug.Assert(a_pixel.X >= 0);
            Debug.Assert(a_pixel.Y >= 0);
            Debug.Assert(a_pixel.X < Film.Width);
            Debug.Assert(a_pixel.Y < Film.Height);

            return new Vector2(a_pixel.X / Film.Width, a_pixel.Y / Film.Height);
        }
    }
}